1 // SPDX-License-Identifier: GPL-2.0 2 3 use kernel::{ 4 device, devres::Devres, error::code::*, firmware, fmt, pci, prelude::*, str::CString, 5 }; 6 7 use crate::driver::Bar0; 8 use crate::regs; 9 use crate::util; 10 use core::fmt; 11 12 macro_rules! define_chipset { 13 ({ $($variant:ident = $value:expr),* $(,)* }) => 14 { 15 /// Enum representation of the GPU chipset. 16 #[derive(fmt::Debug, Copy, Clone, PartialOrd, Ord, PartialEq, Eq)] 17 pub(crate) enum Chipset { 18 $($variant = $value),*, 19 } 20 21 impl Chipset { 22 pub(crate) const ALL: &'static [Chipset] = &[ 23 $( Chipset::$variant, )* 24 ]; 25 26 pub(crate) const NAMES: [&'static str; Self::ALL.len()] = [ 27 $( util::const_bytes_to_str( 28 util::to_lowercase_bytes::<{ stringify!($variant).len() }>( 29 stringify!($variant) 30 ).as_slice() 31 ), )* 32 ]; 33 } 34 35 // TODO replace with something like derive(FromPrimitive) 36 impl TryFrom<u32> for Chipset { 37 type Error = kernel::error::Error; 38 39 fn try_from(value: u32) -> Result<Self, Self::Error> { 40 match value { 41 $( $value => Ok(Chipset::$variant), )* 42 _ => Err(ENODEV), 43 } 44 } 45 } 46 } 47 } 48 49 define_chipset!({ 50 // Turing 51 TU102 = 0x162, 52 TU104 = 0x164, 53 TU106 = 0x166, 54 TU117 = 0x167, 55 TU116 = 0x168, 56 // Ampere 57 GA100 = 0x170, 58 GA102 = 0x172, 59 GA103 = 0x173, 60 GA104 = 0x174, 61 GA106 = 0x176, 62 GA107 = 0x177, 63 // Ada 64 AD102 = 0x192, 65 AD103 = 0x193, 66 AD104 = 0x194, 67 AD106 = 0x196, 68 AD107 = 0x197, 69 }); 70 71 impl Chipset { 72 pub(crate) fn arch(&self) -> Architecture { 73 match self { 74 Self::TU102 | Self::TU104 | Self::TU106 | Self::TU117 | Self::TU116 => { 75 Architecture::Turing 76 } 77 Self::GA100 | Self::GA102 | Self::GA103 | Self::GA104 | Self::GA106 | Self::GA107 => { 78 Architecture::Ampere 79 } 80 Self::AD102 | Self::AD103 | Self::AD104 | Self::AD106 | Self::AD107 => { 81 Architecture::Ada 82 } 83 } 84 } 85 } 86 87 // TODO 88 // 89 // The resulting strings are used to generate firmware paths, hence the 90 // generated strings have to be stable. 91 // 92 // Hence, replace with something like strum_macros derive(Display). 93 // 94 // For now, redirect to fmt::Debug for convenience. 95 impl fmt::Display for Chipset { 96 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 97 write!(f, "{:?}", self) 98 } 99 } 100 101 /// Enum representation of the GPU generation. 102 #[derive(fmt::Debug)] 103 pub(crate) enum Architecture { 104 Turing, 105 Ampere, 106 Ada, 107 } 108 109 pub(crate) struct Revision { 110 major: u8, 111 minor: u8, 112 } 113 114 impl Revision { 115 fn from_boot0(boot0: regs::NV_PMC_BOOT_0) -> Self { 116 Self { 117 major: boot0.major_revision(), 118 minor: boot0.minor_revision(), 119 } 120 } 121 } 122 123 impl fmt::Display for Revision { 124 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 125 write!(f, "{:x}.{:x}", self.major, self.minor) 126 } 127 } 128 129 /// Structure holding the metadata of the GPU. 130 pub(crate) struct Spec { 131 chipset: Chipset, 132 /// The revision of the chipset. 133 revision: Revision, 134 } 135 136 impl Spec { 137 fn new(bar: &Bar0) -> Result<Spec> { 138 let boot0 = regs::NV_PMC_BOOT_0::read(bar); 139 140 Ok(Self { 141 chipset: boot0.chipset()?, 142 revision: Revision::from_boot0(boot0), 143 }) 144 } 145 } 146 147 /// Structure encapsulating the firmware blobs required for the GPU to operate. 148 #[expect(dead_code)] 149 pub(crate) struct Firmware { 150 booter_load: firmware::Firmware, 151 booter_unload: firmware::Firmware, 152 bootloader: firmware::Firmware, 153 gsp: firmware::Firmware, 154 } 155 156 impl Firmware { 157 fn new(dev: &device::Device, spec: &Spec, ver: &str) -> Result<Firmware> { 158 let mut chip_name = CString::try_from_fmt(fmt!("{}", spec.chipset))?; 159 chip_name.make_ascii_lowercase(); 160 161 let request = |name_| { 162 CString::try_from_fmt(fmt!("nvidia/{}/gsp/{}-{}.bin", &*chip_name, name_, ver)) 163 .and_then(|path| firmware::Firmware::request(&path, dev)) 164 }; 165 166 Ok(Firmware { 167 booter_load: request("booter_load")?, 168 booter_unload: request("booter_unload")?, 169 bootloader: request("bootloader")?, 170 gsp: request("gsp")?, 171 }) 172 } 173 } 174 175 /// Structure holding the resources required to operate the GPU. 176 #[pin_data] 177 pub(crate) struct Gpu { 178 spec: Spec, 179 /// MMIO mapping of PCI BAR 0 180 bar: Devres<Bar0>, 181 fw: Firmware, 182 } 183 184 impl Gpu { 185 pub(crate) fn new( 186 pdev: &pci::Device<device::Bound>, 187 devres_bar: Devres<Bar0>, 188 ) -> Result<impl PinInit<Self>> { 189 let bar = devres_bar.access(pdev.as_ref())?; 190 let spec = Spec::new(bar)?; 191 let fw = Firmware::new(pdev.as_ref(), &spec, "535.113.01")?; 192 193 dev_info!( 194 pdev.as_ref(), 195 "NVIDIA (Chipset: {}, Architecture: {:?}, Revision: {})\n", 196 spec.chipset, 197 spec.chipset.arch(), 198 spec.revision 199 ); 200 201 Ok(pin_init!(Self { 202 spec, 203 bar: devres_bar, 204 fw 205 })) 206 } 207 } 208