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)] 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 GA102 = 0x172, 58 GA103 = 0x173, 59 GA104 = 0x174, 60 GA106 = 0x176, 61 GA107 = 0x177, 62 // Ada 63 AD102 = 0x192, 64 AD103 = 0x193, 65 AD104 = 0x194, 66 AD106 = 0x196, 67 AD107 = 0x197, 68 }); 69 70 impl Chipset { arch(&self) -> Architecture71 pub(crate) fn arch(&self) -> Architecture { 72 match self { 73 Self::TU102 | Self::TU104 | Self::TU106 | Self::TU117 | Self::TU116 => { 74 Architecture::Turing 75 } 76 Self::GA102 | Self::GA103 | Self::GA104 | Self::GA106 | Self::GA107 => { 77 Architecture::Ampere 78 } 79 Self::AD102 | Self::AD103 | Self::AD104 | Self::AD106 | Self::AD107 => { 80 Architecture::Ada 81 } 82 } 83 } 84 } 85 86 // TODO 87 // 88 // The resulting strings are used to generate firmware paths, hence the 89 // generated strings have to be stable. 90 // 91 // Hence, replace with something like strum_macros derive(Display). 92 // 93 // For now, redirect to fmt::Debug for convenience. 94 impl fmt::Display for Chipset { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result95 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 96 write!(f, "{self:?}") 97 } 98 } 99 100 /// Enum representation of the GPU generation. 101 #[derive(fmt::Debug)] 102 pub(crate) enum Architecture { 103 Turing, 104 Ampere, 105 Ada, 106 } 107 108 pub(crate) struct Revision { 109 major: u8, 110 minor: u8, 111 } 112 113 impl Revision { from_boot0(boot0: regs::Boot0) -> Self114 fn from_boot0(boot0: regs::Boot0) -> Self { 115 Self { 116 major: boot0.major_rev(), 117 minor: boot0.minor_rev(), 118 } 119 } 120 } 121 122 impl fmt::Display for Revision { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result123 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 124 write!(f, "{:x}.{:x}", self.major, self.minor) 125 } 126 } 127 128 /// Structure holding the metadata of the GPU. 129 pub(crate) struct Spec { 130 chipset: Chipset, 131 /// The revision of the chipset. 132 revision: Revision, 133 } 134 135 impl Spec { new(bar: &Devres<Bar0>) -> Result<Spec>136 fn new(bar: &Devres<Bar0>) -> Result<Spec> { 137 let bar = bar.try_access().ok_or(ENXIO)?; 138 let boot0 = regs::Boot0::read(&bar); 139 140 Ok(Self { 141 chipset: boot0.chipset().try_into()?, 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 { new(dev: &device::Device, spec: &Spec, ver: &str) -> Result<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 { new(pdev: &pci::Device, bar: Devres<Bar0>) -> Result<impl PinInit<Self>>185 pub(crate) fn new(pdev: &pci::Device, bar: Devres<Bar0>) -> Result<impl PinInit<Self>> { 186 let spec = Spec::new(&bar)?; 187 let fw = Firmware::new(pdev.as_ref(), &spec, "535.113.01")?; 188 189 dev_info!( 190 pdev.as_ref(), 191 "NVIDIA (Chipset: {}, Architecture: {:?}, Revision: {})\n", 192 spec.chipset, 193 spec.chipset.arch(), 194 spec.revision 195 ); 196 197 Ok(pin_init!(Self { spec, bar, fw })) 198 } 199 } 200