1 // SPDX-License-Identifier: GPL-2.0 2 3 use core::ops::Range; 4 5 use kernel::{ 6 device, 7 dma::Device, 8 fmt, 9 gpu::buddy::GpuBuddyParams, 10 io::Io, 11 num::Bounded, 12 pci, 13 prelude::*, 14 ptr::Alignment, 15 sizes::{ 16 SizeConstants, 17 SZ_4K, // 18 }, 19 uapi, // 20 }; 21 22 use crate::{ 23 bounded_enum, 24 driver::{ 25 Bar0, 26 Bar1, // 27 }, 28 falcon::{ 29 gsp::Gsp as GspFalcon, 30 sec2::Sec2 as Sec2Falcon, 31 Falcon, // 32 }, 33 fb::SysmemFlush, 34 fsp::Fsp, 35 gsp::{ 36 self, 37 cmdq::Cmdq, 38 commands::GetGspStaticInfoReply, 39 Gsp, 40 GspBootContext, // 41 }, 42 irq::{ 43 self, 44 gsp::GspIrq, 45 interrupt_tree::{ 46 TopEnableGuard, 47 Tree, // 48 }, // 49 }, 50 mm::{ 51 bar_user::BarUser, 52 pagetable::MmuVersion, 53 GpuMm, 54 VramAddress, // 55 }, 56 vgpu::VgpuManager, // 57 }; 58 59 mod hal; 60 mod regs; 61 62 macro_rules! define_chipset { 63 ({ $($variant:ident),* $(,)* }) => 64 { 65 ::kernel::macros::paste!( 66 /// Enum representation of the GPU chipset. 67 #[derive(fmt::Debug, Copy, Clone, PartialOrd, Ord, PartialEq, Eq)] 68 #[repr(u32)] 69 #[allow(missing_docs)] 70 pub enum Chipset { 71 $($variant = uapi::[<drm_nova_chipid_NOVA_DRM_CHIPID_ $variant:upper>]),*, 72 } 73 74 impl Chipset { 75 /// All chipsets known to the driver. 76 pub const ALL: &'static [Chipset] = &[ 77 $( Chipset::$variant, )* 78 ]; 79 80 /// Returns the name of this chipset, in lowercase. 81 /// 82 /// # Examples 83 /// 84 /// ``` 85 /// let chipset = Chipset::GA102; 86 /// assert_eq!(chipset.name(), "ga102"); 87 /// ``` 88 pub(crate) const fn name(&self) -> &'static str { 89 match *self { 90 $( 91 Chipset::$variant => stringify!([<$variant:lower>]), 92 )* 93 } 94 } 95 } 96 97 // TODO[FPRI]: replace with something like derive(FromPrimitive) 98 impl TryFrom<u32> for Chipset { 99 type Error = kernel::error::Error; 100 101 fn try_from(value: u32) -> Result<Self, Self::Error> { 102 match value { 103 $( 104 uapi::[<drm_nova_chipid_NOVA_DRM_CHIPID_ $variant:upper>] => { 105 Ok(Chipset::$variant) 106 } 107 )* 108 _ => Err(ENODEV), 109 } 110 } 111 } 112 ); 113 } 114 } 115 116 define_chipset!({ 117 // Turing 118 TU102, 119 TU104, 120 TU106, 121 TU117, 122 TU116, 123 // Ampere 124 GA100, 125 GA102, 126 GA103, 127 GA104, 128 GA106, 129 GA107, 130 // Hopper 131 GH100, 132 // Ada 133 AD102, 134 AD103, 135 AD104, 136 AD106, 137 AD107, 138 // Blackwell GB10x 139 GB100, 140 GB102, 141 // Blackwell GB20x 142 GB202, 143 GB203, 144 GB205, 145 GB206, 146 GB207, 147 }); 148 149 impl Chipset { 150 /// Returns the [`Architecture`] generation of this chipset. 151 pub const fn arch(self) -> Architecture { 152 match self { 153 Self::TU102 | Self::TU104 | Self::TU106 | Self::TU117 | Self::TU116 => { 154 Architecture::Turing 155 } 156 Self::GA100 | Self::GA102 | Self::GA103 | Self::GA104 | Self::GA106 | Self::GA107 => { 157 Architecture::Ampere 158 } 159 Self::GH100 => Architecture::Hopper, 160 Self::AD102 | Self::AD103 | Self::AD104 | Self::AD106 | Self::AD107 => { 161 Architecture::Ada 162 } 163 Self::GB100 | Self::GB102 => Architecture::BlackwellGB10x, 164 Self::GB202 | Self::GB203 | Self::GB205 | Self::GB206 | Self::GB207 => { 165 Architecture::BlackwellGB20x 166 } 167 } 168 } 169 170 /// Returns the address range of the PCI config mirror space. 171 pub(crate) fn pci_config_mirror_range(self) -> Range<u32> { 172 hal::gpu_hal(self).pci_config_mirror_range() 173 } 174 175 /// Returns the MMU version for this chipset. 176 pub(crate) fn mmu_version(self) -> MmuVersion { 177 MmuVersion::from(self.arch()) 178 } 179 } 180 181 impl From<Chipset> for u32 { 182 #[inline] 183 fn from(value: Chipset) -> Self { 184 // CAST: `Chipset` is `repr(u32)` and can thus be cast losslessly. 185 value as u32 186 } 187 } 188 189 // TODO 190 // 191 // The resulting strings are used to generate firmware paths, hence the 192 // generated strings have to be stable. 193 // 194 // Hence, replace with something like strum_macros derive(Display). 195 // 196 // For now, redirect to fmt::Debug for convenience. 197 impl fmt::Display for Chipset { 198 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 199 write!(f, "{self:?}") 200 } 201 } 202 203 bounded_enum! { 204 /// Enum representation of the GPU generation. 205 #[derive(fmt::Debug, Copy, Clone)] 206 #[repr(u32)] 207 pub enum Architecture with TryFrom<Bounded<u32, 6>> { 208 /// Turing (TU1xx). 209 Turing = uapi::drm_nova_architecture_NOVA_DRM_ARCHITECTURE_TURING, 210 /// Ampere (GA10x). 211 Ampere = uapi::drm_nova_architecture_NOVA_DRM_ARCHITECTURE_AMPERE, 212 /// Hopper (GH100). 213 Hopper = uapi::drm_nova_architecture_NOVA_DRM_ARCHITECTURE_HOPPER, 214 /// Ada Lovelace (AD10x). 215 Ada = uapi::drm_nova_architecture_NOVA_DRM_ARCHITECTURE_ADA, 216 /// Blackwell (GB10x). 217 BlackwellGB10x = 218 uapi::drm_nova_architecture_NOVA_DRM_ARCHITECTURE_BLACKWELL_GB10X, 219 /// Blackwell (GB20x). 220 BlackwellGB20x = 221 uapi::drm_nova_architecture_NOVA_DRM_ARCHITECTURE_BLACKWELL_GB20X, 222 } 223 } 224 225 impl From<Architecture> for u32 { 226 #[inline] 227 fn from(value: Architecture) -> Self { 228 // CAST: `Architecture` is `repr(u32)` and can thus be cast losslessly. 229 value as u32 230 } 231 } 232 233 #[derive(Clone, Copy)] 234 pub(crate) struct Revision { 235 major: Bounded<u8, 4>, 236 minor: Bounded<u8, 4>, 237 } 238 239 impl From<regs::NV_PMC_BOOT_42> for Revision { 240 fn from(boot0: regs::NV_PMC_BOOT_42) -> Self { 241 Self { 242 major: boot0.major_revision().cast(), 243 minor: boot0.minor_revision().cast(), 244 } 245 } 246 } 247 248 impl fmt::Display for Revision { 249 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 250 write!(f, "{:x}.{:x}", self.major, self.minor) 251 } 252 } 253 254 /// Structure holding a basic description of the GPU: `Chipset` and `Revision`. 255 #[derive(Clone, Copy)] 256 pub struct Spec { 257 /// The GPU chipset. 258 pub chipset: Chipset, 259 revision: Revision, 260 } 261 262 impl Spec { 263 pub(crate) fn new(dev: &device::Device, bar: Bar0<'_>) -> Result<Spec> { 264 // Some brief notes about boot0 and boot42, in chronological order: 265 // 266 // NV04 through NV50: 267 // 268 // Not supported by Nova. boot0 is necessary and sufficient to identify these GPUs. 269 // boot42 may not even exist on some of these GPUs. 270 // 271 // Fermi through Volta: 272 // 273 // Not supported by Nova. boot0 is still sufficient to identify these GPUs, but boot42 274 // is also guaranteed to be both present and accurate. 275 // 276 // Turing and later: 277 // 278 // Supported by Nova. Identified by first checking boot0 to ensure that the GPU is not 279 // from an earlier (pre-Fermi) era, and then using boot42 to precisely identify the GPU. 280 // Somewhere in the Rubin timeframe, boot0 will no longer have space to add new GPU IDs. 281 282 let boot0 = bar.read(regs::NV_PMC_BOOT_0); 283 284 if boot0.is_older_than_fermi() { 285 return Err(ENODEV); 286 } 287 288 let boot42 = bar.read(regs::NV_PMC_BOOT_42); 289 Spec::try_from(boot42).inspect_err(|_| { 290 dev_err!(dev, "Unsupported chipset: {}\n", boot42); 291 }) 292 } 293 } 294 295 impl TryFrom<regs::NV_PMC_BOOT_42> for Spec { 296 type Error = Error; 297 298 fn try_from(boot42: regs::NV_PMC_BOOT_42) -> Result<Self> { 299 Ok(Self { 300 chipset: boot42.chipset()?, 301 revision: boot42.into(), 302 }) 303 } 304 } 305 306 impl fmt::Display for Spec { 307 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 308 f.write_fmt(fmt!( 309 "Chipset: {}, Architecture: {:?}, Revision: {}", 310 self.chipset, 311 self.chipset.arch(), 312 self.revision 313 )) 314 } 315 } 316 317 /// Self-contained resources to operate and drop the GSP. 318 #[pin_data(PinnedDrop)] 319 struct GspResources<'gpu> { 320 /// Device owning the GPU. 321 device: &'gpu pci::Device<device::Bound>, 322 /// Details about the chipset. 323 spec: Spec, 324 /// MMIO mapping of PCI BAR 0. 325 bar: Bar0<'gpu>, 326 /// GSP falcon instance, used for GSP boot up and cleanup. 327 gsp_falcon: Falcon<'gpu, GspFalcon>, 328 /// SEC2 falcon instance, used for GSP boot up and cleanup. 329 sec2_falcon: Falcon<'gpu, Sec2Falcon>, 330 /// FSP instance, if on an arch that supports it. 331 // TODO: use different resource types for each boot method, and make the relevant Gsp methods 332 // generic against them. 333 fsp: Option<Fsp<'gpu>>, 334 /// vGPU state detected before GSP boot. 335 vgpu: VgpuManager, 336 /// GSP runtime data. 337 #[pin] 338 gsp: Gsp<'gpu>, 339 /// GSP unload firmware bundle, if any. 340 unload_bundle: Option<gsp::UnloadBundle<'gpu>>, 341 } 342 343 /// The GSP event handler's registration and the enable of its subtree at `TOP`. 344 /// 345 /// The two drop as a unit, the handler first, on the drop of [`Gpu`] and on the error path of 346 /// its constructor alike, so that the subtree is disabled only after the handler is freed. 347 #[pin_data] 348 struct GspSubtree<'a> { 349 #[pin] 350 irq: GspIrq<'a>, 351 /// Must be kept declared *after* `irq`. A handler still in flight enables the subtree again 352 /// through its rearm. 353 _top: TopEnableGuard<'a>, 354 } 355 356 impl<'a> GspSubtree<'a> { 357 /// Returns an initializer that registers the GSP event handler and then enables its subtree at 358 /// `TOP`. 359 /// 360 /// # Safety 361 /// 362 /// Callers must not `mem::forget()` the initialized `GspSubtree` or otherwise prevent its 363 /// [`Drop`] implementation, which runs `free_irq`, from running. 364 unsafe fn new( 365 pdev: &'a pci::Device<device::Bound>, 366 tree: &'a Tree<'a>, 367 falcon: &'a Falcon<'a, GspFalcon>, 368 cmdq: &'a Cmdq<'a>, 369 ) -> impl PinInit<Self, Error> + 'a { 370 try_pin_init!(Self { 371 // SAFETY: this function's caller must not leak the `GspSubtree` that owns this 372 // registration, so the registration's `Drop` runs. 373 irq <- unsafe { GspIrq::new(pdev, tree, falcon, cmdq) }, 374 _top: tree.enable_top_guarded(), 375 }) 376 } 377 } 378 379 /// Structure holding the resources required to operate the GPU. 380 #[pin_data] 381 pub(crate) struct Gpu<'gpu> { 382 pub(crate) spec: Spec, 383 /// GSP event interrupt registration, and the enable of its subtree. 384 /// 385 /// Must be kept declared *before* `gsp_resources`, so that the handler is unregistered, and 386 /// any in-flight run of it has finished, before the command queue that it drains and the 387 /// falcon that it reads are freed, and before the GSP is unloaded. 388 #[pin] 389 _gsp_subtree: GspSubtree<'gpu>, 390 /// Static GPU information as provided by the GSP. 391 pub(crate) gsp_static_info: GetGspStaticInfoReply, 392 /// GPU memory manager owning memory management resources. 393 /// 394 /// Must be kept declared *before* `gsp_resources`, so that its components are dropped while 395 /// the GSP is still operational. 396 mm: GpuMm<'gpu>, 397 /// BAR1 user interface for CPU access to GPU virtual memory. 398 #[pin] 399 bar_user: BarUser<'gpu>, 400 /// GSP and its resources. 401 #[pin] 402 gsp_resources: GspResources<'gpu>, 403 /// System memory page required for flushing all pending GPU-side memory writes done through 404 /// PCIE into system memory, via sysmembar (A GPU-initiated HW memory-barrier operation). 405 /// 406 /// Must be kept declared *after* `gsp_resources`, as the latter's `PinnedDrop` implementation 407 /// requires the sysmem flush page to be in place. 408 sysmem_flush: SysmemFlush<'gpu>, 409 /// Borrow of `tree` that `_gsp_subtree` holds. A field that borrows a sibling field is 410 /// self-referential, which `pin_init` cannot express, so the borrow is taken by hand. 411 tree_ref: &'gpu Tree<'gpu>, 412 /// The GIN CPU interrupt tree and the PCI vectors that deliver it. 413 /// 414 /// Must be kept declared *after* `_gsp_subtree`, which holds a borrow of it. 415 #[pin] 416 tree: Tree<'gpu>, 417 } 418 419 #[pinned_drop] 420 impl PinnedDrop for GspResources<'_> { 421 fn drop(self: Pin<&mut Self>) { 422 let this = self.project(); 423 let device = *this.device; 424 let bar = *this.bar; 425 let bundle = this.unload_bundle.take(); 426 427 let _ = this 428 .gsp 429 .as_ref() 430 .get_ref() 431 .unload( 432 GspBootContext { 433 pdev: device, 434 bar, 435 chipset: this.spec.chipset, 436 gsp_falcon: &*this.gsp_falcon, 437 sec2_falcon: &*this.sec2_falcon, 438 fsp: this.fsp.as_mut(), 439 vgpu: &*this.vgpu, 440 }, 441 bundle, 442 ) 443 .inspect_err(|e| dev_err!(device, "failed to unload GSP: {:?}\n", e)); 444 } 445 } 446 447 impl<'gpu> Gpu<'gpu> { 448 pub(crate) fn new<'a>( 449 pdev: &'gpu pci::Device<device::Core<'a>>, 450 bar: Bar0<'gpu>, 451 bar1: Bar1<'gpu>, 452 ) -> impl PinInit<Self, Error> + use<'gpu, 'a> { 453 let dev = pdev.as_ref(); 454 455 try_pin_init!(Self { 456 spec: Spec::new(dev, bar).inspect(|spec| { 457 dev_info!(dev,"NVIDIA ({})\n", spec); 458 })?, 459 460 tree: Tree::new(pdev, bar, spec.chipset, irq::gsp::GSP_SUBTREE.into())?, 461 462 // SAFETY: `tree` is initialized above, is pinned at a stable address, and is dropped 463 // after every field that uses `tree_ref` (struct field drop order). 464 tree_ref: unsafe { &*core::ptr::from_ref(tree.as_ref().get_ref()) }, 465 466 _: { 467 let dma_mask = hal::gpu_hal(spec.chipset).dma_mask(); 468 469 // SAFETY: `Gpu` owns all DMA allocations for this device, and we are 470 // still constructing it, so no concurrent DMA allocations can exist. 471 unsafe { pdev.dma_set_mask_and_coherent(dma_mask)? }; 472 473 // Nova walks SG segments to build page tables, so their length is 474 // irrelevant to the device. 475 // 476 // SAFETY: `Gpu` owns all DMA allocations for this device, and we are 477 // still constructing it, so no concurrent DMA allocations can exist. 478 unsafe { pdev.dma_set_max_seg_size(u32::MAX) }; 479 480 // We must wait for GFW_BOOT completion before doing any significant setup on the GPU. 481 Self::wait_gfw_boot_completion(dev, bar, spec.chipset)?; 482 }, 483 484 // Initialize this early because `gsp_resources` depends on it. 485 sysmem_flush: SysmemFlush::register(dev, bar, spec.chipset)?, 486 487 gsp_resources <- try_pin_init!(GspResources { 488 device: pdev, 489 490 spec: *spec, 491 492 bar, 493 494 gsp_falcon: Falcon::new(dev, spec.chipset, bar)?, 495 496 sec2_falcon: Falcon::new(dev, spec.chipset, bar)?, 497 498 fsp: Fsp::try_new(dev, bar, spec.chipset)?, 499 500 vgpu: VgpuManager::new(pdev, spec.chipset, fsp.as_mut()), 501 502 gsp <- Gsp::new(pdev, bar), 503 504 // This member must be initialized last, so the `UnloadBundle` can never be dropped 505 // from outside of the constructed `GspResources`, ensuring that the unload sequence 506 // is properly run in case of failure. 507 unload_bundle: gsp.boot(GspBootContext { 508 pdev, 509 bar, 510 chipset: spec.chipset, 511 gsp_falcon, 512 sec2_falcon, 513 fsp: fsp.as_mut(), 514 vgpu, 515 })?, 516 }), 517 518 _: { 519 irq::gsp::quiesce(tree_ref, &gsp_resources.gsp_falcon); 520 }, 521 522 // SAFETY: the GSP falcon and the command queue are fields of `gsp_resources`, which 523 // is initialized above and pinned, so both references outlive the registration. The 524 // registration is a field of `Gpu` and is never leaked, so its `Drop` runs, and field 525 // drop order runs it before either is freed. 526 _gsp_subtree <- unsafe { 527 GspSubtree::new( 528 pdev, 529 tree_ref, 530 &*core::ptr::from_ref(&gsp_resources.gsp_falcon), 531 &*core::ptr::from_ref(&gsp_resources.gsp.cmdq), 532 ) 533 }, 534 535 // No interrupt announces the messages that the GSP posted during boot, before the 536 // SWGEN0 latch was cleared. 537 _: { 538 gsp_resources.gsp.cmdq.drain()?; 539 }, 540 541 gsp_static_info: { 542 // Obtain and display basic GPU information. 543 let info = gsp_resources.gsp.get_static_info()?; 544 match info.gpu_name() { 545 Ok(name) => dev_info!(dev, "GPU name: {}\n", name), 546 Err(e) => dev_warn!(dev, "GPU name unavailable: {:?}\n", e), 547 } 548 549 if !info.usable_fb_regions.is_empty() { 550 dev_dbg!(dev, "Usable FB regions:\n"); 551 for region in &info.usable_fb_regions { 552 dev_dbg!(dev, " - {:#x?}\n", region); 553 } 554 555 dev_dbg!( 556 dev, 557 "Total usable VRAM: {} MiB\n", 558 info.vram_size() / u64::SZ_1M 559 ); 560 } 561 562 info 563 }, 564 565 // Create GPU memory manager owning memory management resources. 566 mm: { 567 let usable_vram = gsp_static_info.usable_fb_regions.first().ok_or(ENODEV)?; 568 let buddy_params = GpuBuddyParams { 569 base_offset: usable_vram.start, 570 size: usable_vram.end - usable_vram.start, 571 chunk_size: Alignment::new::<SZ_4K>(), 572 }; 573 574 GpuMm::new( 575 bar, 576 gsp_resources.spec.chipset, 577 buddy_params, 578 VramAddress::from_raw(gsp_static_info.total_fb_end), 579 )? 580 }, 581 582 // Create BAR1 user interface for CPU access to GPU virtual memory. 583 bar_user <- { 584 let pdb_addr = VramAddress::from_raw(gsp_static_info.bar1_pde_base); 585 let bar1_idx = crate::driver::bar1_resource_index(pdev)?; 586 let bar1_size = pdev.resource_len(bar1_idx)?; 587 588 BarUser::new( 589 pdb_addr, 590 gsp_resources.spec.chipset, 591 bar1_size, 592 bar1, 593 ) 594 }, 595 }) 596 } 597 598 /// Waits for GFW, the GPU's boot firmware, to report completion. 599 /// 600 /// The driver must not program the GPU before then. 601 /// 602 /// # Errors 603 /// 604 /// `ETIMEDOUT` if GFW does not report completion in time. 605 pub(crate) fn wait_gfw_boot_completion( 606 dev: &device::Device<device::Bound>, 607 bar: Bar0<'_>, 608 chipset: Chipset, 609 ) -> Result { 610 hal::gpu_hal(chipset) 611 .wait_gfw_boot_completion(bar) 612 .inspect_err(|_| dev_err!(dev, "GFW boot did not complete\n")) 613 } 614 615 /// Runs self-tests on the constructed [`Gpu`], logging failures without failing probe. 616 #[cfg(CONFIG_NOVA_CORE_SELFTESTS)] 617 pub(crate) fn run_selftests(self: Pin<&mut Self>, pdev: &pci::Device<device::Bound>) { 618 let this = self.project(); 619 let dev = pdev.as_ref(); 620 let regions = &this.gsp_static_info.usable_fb_regions; 621 622 if let Err(err) = crate::mm::selftest::run( 623 dev, 624 this.mm, 625 regions, 626 &this.bar_user, 627 this.gsp_static_info.bar1_pde_base, 628 this.spec.chipset, 629 ) { 630 dev_err!(dev, "self-tests failed: {:?}\n", err); 631 } 632 } 633 } 634 635 /// Reads the boot0 register and returns its raw value. 636 pub(crate) fn boot_0_raw(bar: Bar0<'_>) -> u32 { 637 bar.read(regs::NV_PMC_BOOT_0).into_raw() 638 } 639