1 // SPDX-License-Identifier: GPL-2.0 2 3 use kernel::{device, devres::Devres, error::code::*, pci, prelude::*, sync::Arc}; 4 5 use crate::driver::Bar0; 6 use crate::falcon::{gsp::Gsp as GspFalcon, sec2::Sec2 as Sec2Falcon, Falcon}; 7 use crate::fb::SysmemFlush; 8 use crate::gfw; 9 use crate::gsp::Gsp; 10 use crate::regs; 11 use core::fmt; 12 13 macro_rules! define_chipset { 14 ({ $($variant:ident = $value:expr),* $(,)* }) => 15 { 16 /// Enum representation of the GPU chipset. 17 #[derive(fmt::Debug, Copy, Clone, PartialOrd, Ord, PartialEq, Eq)] 18 pub(crate) enum Chipset { 19 $($variant = $value),*, 20 } 21 22 impl Chipset { 23 pub(crate) const ALL: &'static [Chipset] = &[ 24 $( Chipset::$variant, )* 25 ]; 26 27 ::kernel::macros::paste!( 28 /// Returns the name of this chipset, in lowercase. 29 /// 30 /// # Examples 31 /// 32 /// ``` 33 /// let chipset = Chipset::GA102; 34 /// assert_eq!(chipset.name(), "ga102"); 35 /// ``` 36 pub(crate) const fn name(&self) -> &'static str { 37 match *self { 38 $( 39 Chipset::$variant => stringify!([<$variant:lower>]), 40 )* 41 } 42 } 43 ); 44 } 45 46 // TODO[FPRI]: replace with something like derive(FromPrimitive) 47 impl TryFrom<u32> for Chipset { 48 type Error = kernel::error::Error; 49 50 fn try_from(value: u32) -> Result<Self, Self::Error> { 51 match value { 52 $( $value => Ok(Chipset::$variant), )* 53 _ => Err(ENODEV), 54 } 55 } 56 } 57 } 58 } 59 60 define_chipset!({ 61 // Turing 62 TU102 = 0x162, 63 TU104 = 0x164, 64 TU106 = 0x166, 65 TU117 = 0x167, 66 TU116 = 0x168, 67 // Ampere 68 GA100 = 0x170, 69 GA102 = 0x172, 70 GA103 = 0x173, 71 GA104 = 0x174, 72 GA106 = 0x176, 73 GA107 = 0x177, 74 // Ada 75 AD102 = 0x192, 76 AD103 = 0x193, 77 AD104 = 0x194, 78 AD106 = 0x196, 79 AD107 = 0x197, 80 }); 81 82 impl Chipset { 83 pub(crate) fn arch(&self) -> Architecture { 84 match self { 85 Self::TU102 | Self::TU104 | Self::TU106 | Self::TU117 | Self::TU116 => { 86 Architecture::Turing 87 } 88 Self::GA100 | Self::GA102 | Self::GA103 | Self::GA104 | Self::GA106 | Self::GA107 => { 89 Architecture::Ampere 90 } 91 Self::AD102 | Self::AD103 | Self::AD104 | Self::AD106 | Self::AD107 => { 92 Architecture::Ada 93 } 94 } 95 } 96 } 97 98 // TODO 99 // 100 // The resulting strings are used to generate firmware paths, hence the 101 // generated strings have to be stable. 102 // 103 // Hence, replace with something like strum_macros derive(Display). 104 // 105 // For now, redirect to fmt::Debug for convenience. 106 impl fmt::Display for Chipset { 107 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 108 write!(f, "{self:?}") 109 } 110 } 111 112 /// Enum representation of the GPU generation. 113 #[derive(fmt::Debug)] 114 pub(crate) enum Architecture { 115 Turing = 0x16, 116 Ampere = 0x17, 117 Ada = 0x19, 118 } 119 120 impl TryFrom<u8> for Architecture { 121 type Error = Error; 122 123 fn try_from(value: u8) -> Result<Self> { 124 match value { 125 0x16 => Ok(Self::Turing), 126 0x17 => Ok(Self::Ampere), 127 0x19 => Ok(Self::Ada), 128 _ => Err(ENODEV), 129 } 130 } 131 } 132 133 pub(crate) struct Revision { 134 major: u8, 135 minor: u8, 136 } 137 138 impl Revision { 139 fn from_boot0(boot0: regs::NV_PMC_BOOT_0) -> Self { 140 Self { 141 major: boot0.major_revision(), 142 minor: boot0.minor_revision(), 143 } 144 } 145 } 146 147 impl fmt::Display for Revision { 148 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 149 write!(f, "{:x}.{:x}", self.major, self.minor) 150 } 151 } 152 153 /// Structure holding the metadata of the GPU. 154 pub(crate) struct Spec { 155 chipset: Chipset, 156 /// The revision of the chipset. 157 revision: Revision, 158 } 159 160 impl Spec { 161 fn new(bar: &Bar0) -> Result<Spec> { 162 let boot0 = regs::NV_PMC_BOOT_0::read(bar); 163 164 Ok(Self { 165 chipset: boot0.chipset()?, 166 revision: Revision::from_boot0(boot0), 167 }) 168 } 169 } 170 171 /// Structure holding the resources required to operate the GPU. 172 #[pin_data] 173 pub(crate) struct Gpu { 174 spec: Spec, 175 /// MMIO mapping of PCI BAR 0 176 bar: Arc<Devres<Bar0>>, 177 /// System memory page required for flushing all pending GPU-side memory writes done through 178 /// PCIE into system memory, via sysmembar (A GPU-initiated HW memory-barrier operation). 179 sysmem_flush: SysmemFlush, 180 /// GSP falcon instance, used for GSP boot up and cleanup. 181 gsp_falcon: Falcon<GspFalcon>, 182 /// SEC2 falcon instance, used for GSP boot up and cleanup. 183 sec2_falcon: Falcon<Sec2Falcon>, 184 /// GSP runtime data. Temporarily an empty placeholder. 185 #[pin] 186 gsp: Gsp, 187 } 188 189 impl Gpu { 190 pub(crate) fn new<'a>( 191 pdev: &'a pci::Device<device::Bound>, 192 devres_bar: Arc<Devres<Bar0>>, 193 bar: &'a Bar0, 194 ) -> impl PinInit<Self, Error> + 'a { 195 try_pin_init!(Self { 196 spec: Spec::new(bar).inspect(|spec| { 197 dev_info!( 198 pdev.as_ref(), 199 "NVIDIA (Chipset: {}, Architecture: {:?}, Revision: {})\n", 200 spec.chipset, 201 spec.chipset.arch(), 202 spec.revision 203 ); 204 })?, 205 206 // We must wait for GFW_BOOT completion before doing any significant setup on the GPU. 207 _: { 208 gfw::wait_gfw_boot_completion(bar) 209 .inspect_err(|_| dev_err!(pdev.as_ref(), "GFW boot did not complete"))?; 210 }, 211 212 sysmem_flush: SysmemFlush::register(pdev.as_ref(), bar, spec.chipset)?, 213 214 gsp_falcon: Falcon::new( 215 pdev.as_ref(), 216 spec.chipset, 217 bar, 218 spec.chipset > Chipset::GA100, 219 ) 220 .inspect(|falcon| falcon.clear_swgen0_intr(bar))?, 221 222 sec2_falcon: Falcon::new(pdev.as_ref(), spec.chipset, bar, true)?, 223 224 gsp <- Gsp::new(), 225 226 _: { gsp.boot(pdev, bar, spec.chipset, gsp_falcon, sec2_falcon)? }, 227 228 bar: devres_bar, 229 }) 230 } 231 232 /// Called when the corresponding [`Device`](device::Device) is unbound. 233 /// 234 /// Note: This method must only be called from `Driver::unbind`. 235 pub(crate) fn unbind(&self, dev: &device::Device<device::Core>) { 236 kernel::warn_on!(self 237 .bar 238 .access(dev) 239 .inspect(|bar| self.sysmem_flush.unregister(bar)) 240 .is_err()); 241 } 242 } 243