1 // SPDX-License-Identifier: GPL-2.0 2 // SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 4 use kernel::prelude::*; 5 6 use crate::{ 7 falcon::{ 8 Falcon, 9 FalconBromParams, 10 FalconEngine, // 11 }, 12 gpu::{ 13 Architecture, 14 Chipset, // 15 }, 16 regs, 17 }; 18 19 mod ga102; 20 mod tu102; 21 22 /// Method used to load data into falcon memory. Some GPU architectures need 23 /// PIO and others can use DMA. 24 pub(crate) enum LoadMethod { 25 /// Programmed I/O 26 Pio, 27 /// Direct Memory Access 28 Dma, 29 } 30 31 /// Hardware Abstraction Layer for Falcon cores. 32 /// 33 /// Implements chipset-specific low-level operations. The trait is generic against [`FalconEngine`] 34 /// so its `BASE` parameter can be used in order to avoid runtime bound checks when accessing 35 /// registers. 36 pub(crate) trait FalconHal<E: FalconEngine>: Send + Sync { 37 /// Activates the Falcon core if the engine is a risvc/falcon dual engine. 38 fn select_core(&self, _falcon: &Falcon<'_, E>) -> Result { 39 Ok(()) 40 } 41 42 /// Returns the fused version of the signature to use in order to run a HS firmware on this 43 /// falcon instance. `engine_id_mask` and `ucode_id` are obtained from the firmware header. 44 fn signature_reg_fuse_version( 45 &self, 46 falcon: &Falcon<'_, E>, 47 engine_id_mask: u16, 48 ucode_id: u8, 49 ) -> Result<u32>; 50 51 /// Program the boot ROM registers prior to starting a secure firmware. 52 fn program_brom(&self, falcon: &Falcon<'_, E>, params: &FalconBromParams); 53 54 /// Check if the RISC-V core is active. 55 /// Returns `true` if the RISC-V core is active, `false` otherwise. 56 fn is_riscv_active(&self, falcon: &Falcon<'_, E>) -> bool; 57 58 /// Checks whether the RISC-V core is halted. 59 /// 60 /// Returns [`ENOTSUPP`] if the chipset does not expose RISC-V halt status. 61 fn is_riscv_halted(&self, falcon: &Falcon<'_, E>) -> Result<bool>; 62 63 /// Wait for memory scrubbing to complete. 64 fn reset_wait_mem_scrubbing(&self, falcon: &Falcon<'_, E>) -> Result; 65 66 /// Reset the falcon engine. 67 fn reset_eng(&self, falcon: &Falcon<'_, E>) -> Result; 68 69 /// Returns the method used to load data into the falcon's memory. 70 /// 71 /// The only chipsets supporting PIO are those < GA102, and PIO is the preferred method for 72 /// these. For anything above, the PIO registers appear to be masked to the CPU, so DMA is the 73 /// only usable method. 74 fn load_method(&self) -> LoadMethod; 75 76 /// Returns the causes in `latched` that are routed to the host, meaning the CPU, rather than 77 /// to the falcon's own RISC-V core. 78 /// 79 /// The causes routed to the core belong to the firmware running on it, and the host does not 80 /// service them. 81 fn host_routed_causes( 82 &self, 83 falcon: &Falcon<'_, E>, 84 latched: regs::NV_PFALCON_FALCON_IRQSTAT, 85 ) -> regs::NV_PFALCON_FALCON_IRQSTAT; 86 87 /// Retriggers the falcon, which then re-emits its host-routed causes into the interrupt tree. 88 fn retrigger(&self, falcon: &Falcon<'_, E>); 89 } 90 91 /// Returns a boxed falcon HAL adequate for `chipset`. 92 /// 93 /// We use a heap-allocated trait object instead of a statically defined one because the 94 /// generic `FalconEngine` argument makes it difficult to define all the combinations 95 /// statically. 96 pub(super) fn falcon_hal<E: FalconEngine + 'static>( 97 chipset: Chipset, 98 ) -> Result<KBox<dyn FalconHal<E>>> { 99 let hal = match chipset.arch() { 100 Architecture::Turing => { 101 KBox::new(tu102::Tu102::<E>::new(false), GFP_KERNEL)? as KBox<dyn FalconHal<E>> 102 } 103 // GA100 boots like Turing, but features the retrigger register. 104 Architecture::Ampere if chipset == Chipset::GA100 => { 105 KBox::new(tu102::Tu102::<E>::new(true), GFP_KERNEL)? as KBox<dyn FalconHal<E>> 106 } 107 Architecture::Ampere 108 | Architecture::Ada 109 | Architecture::Hopper 110 | Architecture::BlackwellGB10x 111 | Architecture::BlackwellGB20x => { 112 KBox::new(ga102::Ga102::<E>::new(), GFP_KERNEL)? as KBox<dyn FalconHal<E>> 113 } 114 }; 115 116 Ok(hal) 117 } 118