xref: /linux-6.15/drivers/gpu/nova-core/gpu.rs (revision 211dcf77)
154e6baf1SDanilo Krummrich // SPDX-License-Identifier: GPL-2.0
254e6baf1SDanilo Krummrich 
354e6baf1SDanilo Krummrich use kernel::{
454e6baf1SDanilo Krummrich     device, devres::Devres, error::code::*, firmware, fmt, pci, prelude::*, str::CString,
554e6baf1SDanilo Krummrich };
654e6baf1SDanilo Krummrich 
754e6baf1SDanilo Krummrich use crate::driver::Bar0;
854e6baf1SDanilo Krummrich use crate::regs;
954e6baf1SDanilo Krummrich use crate::util;
1054e6baf1SDanilo Krummrich use core::fmt;
1154e6baf1SDanilo Krummrich 
1254e6baf1SDanilo Krummrich macro_rules! define_chipset {
1354e6baf1SDanilo Krummrich     ({ $($variant:ident = $value:expr),* $(,)* }) =>
1454e6baf1SDanilo Krummrich     {
1554e6baf1SDanilo Krummrich         /// Enum representation of the GPU chipset.
1654e6baf1SDanilo Krummrich         #[derive(fmt::Debug)]
1754e6baf1SDanilo Krummrich         pub(crate) enum Chipset {
1854e6baf1SDanilo Krummrich             $($variant = $value),*,
1954e6baf1SDanilo Krummrich         }
2054e6baf1SDanilo Krummrich 
2154e6baf1SDanilo Krummrich         impl Chipset {
2254e6baf1SDanilo Krummrich             pub(crate) const ALL: &'static [Chipset] = &[
2354e6baf1SDanilo Krummrich                 $( Chipset::$variant, )*
2454e6baf1SDanilo Krummrich             ];
2554e6baf1SDanilo Krummrich 
2654e6baf1SDanilo Krummrich             pub(crate) const NAMES: [&'static str; Self::ALL.len()] = [
2754e6baf1SDanilo Krummrich                 $( util::const_bytes_to_str(
2854e6baf1SDanilo Krummrich                         util::to_lowercase_bytes::<{ stringify!($variant).len() }>(
2954e6baf1SDanilo Krummrich                             stringify!($variant)
3054e6baf1SDanilo Krummrich                         ).as_slice()
3154e6baf1SDanilo Krummrich                 ), )*
3254e6baf1SDanilo Krummrich             ];
3354e6baf1SDanilo Krummrich         }
3454e6baf1SDanilo Krummrich 
3554e6baf1SDanilo Krummrich         // TODO replace with something like derive(FromPrimitive)
3654e6baf1SDanilo Krummrich         impl TryFrom<u32> for Chipset {
3754e6baf1SDanilo Krummrich             type Error = kernel::error::Error;
3854e6baf1SDanilo Krummrich 
3954e6baf1SDanilo Krummrich             fn try_from(value: u32) -> Result<Self, Self::Error> {
4054e6baf1SDanilo Krummrich                 match value {
4154e6baf1SDanilo Krummrich                     $( $value => Ok(Chipset::$variant), )*
4254e6baf1SDanilo Krummrich                     _ => Err(ENODEV),
4354e6baf1SDanilo Krummrich                 }
4454e6baf1SDanilo Krummrich             }
4554e6baf1SDanilo Krummrich         }
4654e6baf1SDanilo Krummrich     }
4754e6baf1SDanilo Krummrich }
4854e6baf1SDanilo Krummrich 
4954e6baf1SDanilo Krummrich define_chipset!({
5054e6baf1SDanilo Krummrich     // Turing
5154e6baf1SDanilo Krummrich     TU102 = 0x162,
5254e6baf1SDanilo Krummrich     TU104 = 0x164,
5354e6baf1SDanilo Krummrich     TU106 = 0x166,
5454e6baf1SDanilo Krummrich     TU117 = 0x167,
5554e6baf1SDanilo Krummrich     TU116 = 0x168,
5654e6baf1SDanilo Krummrich     // Ampere
5754e6baf1SDanilo Krummrich     GA102 = 0x172,
5854e6baf1SDanilo Krummrich     GA103 = 0x173,
5954e6baf1SDanilo Krummrich     GA104 = 0x174,
6054e6baf1SDanilo Krummrich     GA106 = 0x176,
6154e6baf1SDanilo Krummrich     GA107 = 0x177,
6254e6baf1SDanilo Krummrich     // Ada
6354e6baf1SDanilo Krummrich     AD102 = 0x192,
6454e6baf1SDanilo Krummrich     AD103 = 0x193,
6554e6baf1SDanilo Krummrich     AD104 = 0x194,
6654e6baf1SDanilo Krummrich     AD106 = 0x196,
6754e6baf1SDanilo Krummrich     AD107 = 0x197,
6854e6baf1SDanilo Krummrich });
6954e6baf1SDanilo Krummrich 
7054e6baf1SDanilo Krummrich impl Chipset {
arch(&self) -> Architecture7154e6baf1SDanilo Krummrich     pub(crate) fn arch(&self) -> Architecture {
7254e6baf1SDanilo Krummrich         match self {
7354e6baf1SDanilo Krummrich             Self::TU102 | Self::TU104 | Self::TU106 | Self::TU117 | Self::TU116 => {
7454e6baf1SDanilo Krummrich                 Architecture::Turing
7554e6baf1SDanilo Krummrich             }
7654e6baf1SDanilo Krummrich             Self::GA102 | Self::GA103 | Self::GA104 | Self::GA106 | Self::GA107 => {
7754e6baf1SDanilo Krummrich                 Architecture::Ampere
7854e6baf1SDanilo Krummrich             }
7954e6baf1SDanilo Krummrich             Self::AD102 | Self::AD103 | Self::AD104 | Self::AD106 | Self::AD107 => {
8054e6baf1SDanilo Krummrich                 Architecture::Ada
8154e6baf1SDanilo Krummrich             }
8254e6baf1SDanilo Krummrich         }
8354e6baf1SDanilo Krummrich     }
8454e6baf1SDanilo Krummrich }
8554e6baf1SDanilo Krummrich 
8654e6baf1SDanilo Krummrich // TODO
8754e6baf1SDanilo Krummrich //
8854e6baf1SDanilo Krummrich // The resulting strings are used to generate firmware paths, hence the
8954e6baf1SDanilo Krummrich // generated strings have to be stable.
9054e6baf1SDanilo Krummrich //
9154e6baf1SDanilo Krummrich // Hence, replace with something like strum_macros derive(Display).
9254e6baf1SDanilo Krummrich //
9354e6baf1SDanilo Krummrich // For now, redirect to fmt::Debug for convenience.
9454e6baf1SDanilo Krummrich impl fmt::Display for Chipset {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result9554e6baf1SDanilo Krummrich     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
96*211dcf77SMiguel Ojeda         write!(f, "{self:?}")
9754e6baf1SDanilo Krummrich     }
9854e6baf1SDanilo Krummrich }
9954e6baf1SDanilo Krummrich 
10054e6baf1SDanilo Krummrich /// Enum representation of the GPU generation.
10154e6baf1SDanilo Krummrich #[derive(fmt::Debug)]
10254e6baf1SDanilo Krummrich pub(crate) enum Architecture {
10354e6baf1SDanilo Krummrich     Turing,
10454e6baf1SDanilo Krummrich     Ampere,
10554e6baf1SDanilo Krummrich     Ada,
10654e6baf1SDanilo Krummrich }
10754e6baf1SDanilo Krummrich 
10854e6baf1SDanilo Krummrich pub(crate) struct Revision {
10954e6baf1SDanilo Krummrich     major: u8,
11054e6baf1SDanilo Krummrich     minor: u8,
11154e6baf1SDanilo Krummrich }
11254e6baf1SDanilo Krummrich 
11354e6baf1SDanilo Krummrich impl Revision {
from_boot0(boot0: regs::Boot0) -> Self11454e6baf1SDanilo Krummrich     fn from_boot0(boot0: regs::Boot0) -> Self {
11554e6baf1SDanilo Krummrich         Self {
11654e6baf1SDanilo Krummrich             major: boot0.major_rev(),
11754e6baf1SDanilo Krummrich             minor: boot0.minor_rev(),
11854e6baf1SDanilo Krummrich         }
11954e6baf1SDanilo Krummrich     }
12054e6baf1SDanilo Krummrich }
12154e6baf1SDanilo Krummrich 
12254e6baf1SDanilo Krummrich impl fmt::Display for Revision {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result12354e6baf1SDanilo Krummrich     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
12454e6baf1SDanilo Krummrich         write!(f, "{:x}.{:x}", self.major, self.minor)
12554e6baf1SDanilo Krummrich     }
12654e6baf1SDanilo Krummrich }
12754e6baf1SDanilo Krummrich 
12854e6baf1SDanilo Krummrich /// Structure holding the metadata of the GPU.
12954e6baf1SDanilo Krummrich pub(crate) struct Spec {
13054e6baf1SDanilo Krummrich     chipset: Chipset,
13154e6baf1SDanilo Krummrich     /// The revision of the chipset.
13254e6baf1SDanilo Krummrich     revision: Revision,
13354e6baf1SDanilo Krummrich }
13454e6baf1SDanilo Krummrich 
13554e6baf1SDanilo Krummrich impl Spec {
new(bar: &Devres<Bar0>) -> Result<Spec>13654e6baf1SDanilo Krummrich     fn new(bar: &Devres<Bar0>) -> Result<Spec> {
13754e6baf1SDanilo Krummrich         let bar = bar.try_access().ok_or(ENXIO)?;
13854e6baf1SDanilo Krummrich         let boot0 = regs::Boot0::read(&bar);
13954e6baf1SDanilo Krummrich 
14054e6baf1SDanilo Krummrich         Ok(Self {
14154e6baf1SDanilo Krummrich             chipset: boot0.chipset().try_into()?,
14254e6baf1SDanilo Krummrich             revision: Revision::from_boot0(boot0),
14354e6baf1SDanilo Krummrich         })
14454e6baf1SDanilo Krummrich     }
14554e6baf1SDanilo Krummrich }
14654e6baf1SDanilo Krummrich 
14754e6baf1SDanilo Krummrich /// Structure encapsulating the firmware blobs required for the GPU to operate.
14854e6baf1SDanilo Krummrich #[expect(dead_code)]
14954e6baf1SDanilo Krummrich pub(crate) struct Firmware {
15054e6baf1SDanilo Krummrich     booter_load: firmware::Firmware,
15154e6baf1SDanilo Krummrich     booter_unload: firmware::Firmware,
15254e6baf1SDanilo Krummrich     bootloader: firmware::Firmware,
15354e6baf1SDanilo Krummrich     gsp: firmware::Firmware,
15454e6baf1SDanilo Krummrich }
15554e6baf1SDanilo Krummrich 
15654e6baf1SDanilo Krummrich impl Firmware {
new(dev: &device::Device, spec: &Spec, ver: &str) -> Result<Firmware>15754e6baf1SDanilo Krummrich     fn new(dev: &device::Device, spec: &Spec, ver: &str) -> Result<Firmware> {
15854e6baf1SDanilo Krummrich         let mut chip_name = CString::try_from_fmt(fmt!("{}", spec.chipset))?;
15954e6baf1SDanilo Krummrich         chip_name.make_ascii_lowercase();
16054e6baf1SDanilo Krummrich 
16154e6baf1SDanilo Krummrich         let request = |name_| {
16254e6baf1SDanilo Krummrich             CString::try_from_fmt(fmt!("nvidia/{}/gsp/{}-{}.bin", &*chip_name, name_, ver))
16354e6baf1SDanilo Krummrich                 .and_then(|path| firmware::Firmware::request(&path, dev))
16454e6baf1SDanilo Krummrich         };
16554e6baf1SDanilo Krummrich 
16654e6baf1SDanilo Krummrich         Ok(Firmware {
16754e6baf1SDanilo Krummrich             booter_load: request("booter_load")?,
16854e6baf1SDanilo Krummrich             booter_unload: request("booter_unload")?,
16954e6baf1SDanilo Krummrich             bootloader: request("bootloader")?,
17054e6baf1SDanilo Krummrich             gsp: request("gsp")?,
17154e6baf1SDanilo Krummrich         })
17254e6baf1SDanilo Krummrich     }
17354e6baf1SDanilo Krummrich }
17454e6baf1SDanilo Krummrich 
17554e6baf1SDanilo Krummrich /// Structure holding the resources required to operate the GPU.
17654e6baf1SDanilo Krummrich #[pin_data]
17754e6baf1SDanilo Krummrich pub(crate) struct Gpu {
17854e6baf1SDanilo Krummrich     spec: Spec,
17954e6baf1SDanilo Krummrich     /// MMIO mapping of PCI BAR 0
18054e6baf1SDanilo Krummrich     bar: Devres<Bar0>,
18154e6baf1SDanilo Krummrich     fw: Firmware,
18254e6baf1SDanilo Krummrich }
18354e6baf1SDanilo Krummrich 
18454e6baf1SDanilo Krummrich impl Gpu {
new(pdev: &pci::Device, bar: Devres<Bar0>) -> Result<impl PinInit<Self>>18554e6baf1SDanilo Krummrich     pub(crate) fn new(pdev: &pci::Device, bar: Devres<Bar0>) -> Result<impl PinInit<Self>> {
18654e6baf1SDanilo Krummrich         let spec = Spec::new(&bar)?;
18754e6baf1SDanilo Krummrich         let fw = Firmware::new(pdev.as_ref(), &spec, "535.113.01")?;
18854e6baf1SDanilo Krummrich 
18954e6baf1SDanilo Krummrich         dev_info!(
19054e6baf1SDanilo Krummrich             pdev.as_ref(),
19154e6baf1SDanilo Krummrich             "NVIDIA (Chipset: {}, Architecture: {:?}, Revision: {})\n",
19254e6baf1SDanilo Krummrich             spec.chipset,
19354e6baf1SDanilo Krummrich             spec.chipset.arch(),
19454e6baf1SDanilo Krummrich             spec.revision
19554e6baf1SDanilo Krummrich         );
19654e6baf1SDanilo Krummrich 
19754e6baf1SDanilo Krummrich         Ok(pin_init!(Self { spec, bar, fw }))
19854e6baf1SDanilo Krummrich     }
19954e6baf1SDanilo Krummrich }
200